package com.mcptt.http.auth.process.digest;

import com.cloudptt.api.product.log.Log;
import com.mcptt.http.auth.process.HttpAuthFailedException;
import com.mcptt.http.auth.process.HttpSubProcessor;
import com.mcptt.http.auth.process.digest.result.FirstGetResult;
import com.mcptt.http.auth.process.digest.result.SecondGetResult;
import com.mcptt.http.auth.process.digest.result.ThirdGetResult;
import com.mcptt.http.auth.process.result.FinalResult;
import com.mcptt.http.tool.EncryptionTool;

import java.net.URI;
import java.util.HashMap;
import java.util.Map;

import okhttp3.Response;

public class HttpDigestSubProcessor extends HttpSubProcessor
{
	public HttpDigestSubProcessor(URI authUri, URI loginUri, URI tokenUri)
	{
		super(authUri,loginUri,tokenUri);
	}
	public void runAuthorization(String clientId, String redirectUri,String mcId,String pwd) throws Exception
	{
		Log.debug(this.getClass(), "doAuthorization clientId = " + clientId + " redirectUri = " + redirectUri + " mcId = " + mcId);
		String state = getState();
		FirstGetResult firstResult = doFirstGet(clientId, redirectUri,state);
		Log.debug(this.getClass(), "firstResult = " + firstResult);
		if(!firstResult.isSuc())
		{
			String errStr = firstResult.getErrStr();
			Exception e =  new HttpAuthFailedException("doFirstGet",errStr);
			sendAuthResultMsg(AUTH_FAILED,e);
		}
		if(!firstResult.checkReturnParamOk())
		{
			Exception e = new HttpAuthFailedException("doFirstGet","Return Param less");
			sendAuthResultMsg(AUTH_FAILED,e);
		}

		String url = firstResult.getLocation();
		String newUrl = getUrl(url);
		String cookie = firstResult.getCookie();
		SecondGetResult secondResult = doSecondGet(newUrl, cookie);
		Log.debug(this.getClass(), "secondResult = " + secondResult);
		if(!secondResult.isSuc())
		{
			String errStr = secondResult.getErrStr();
			Exception e =  new HttpAuthFailedException("doSecondGet",errStr);
			sendAuthResultMsg(AUTH_FAILED,e);
		}
		if(!secondResult.checkReturnParamOk())
		{
			Exception e =  new HttpAuthFailedException("doSecondGet","Return Param less");
			sendAuthResultMsg(AUTH_FAILED,e);
		}
		Log.debug(this.getClass(), "doThirdGet url = " + url);
		secondResult.generateDigestAuth(mcId, pwd,"as/authorization.oauth2");
		ThirdGetResult thirdResult = doThirdGet(newUrl, cookie, secondResult.getAuthInfoDscp());
		Log.debug(this.getClass(), "thirdResult = " + thirdResult);
		if(!thirdResult.isSuc())
		{
			String errStr = thirdResult.getErrStr();
			Exception e =  new HttpAuthFailedException("doThirdGet",errStr);
			sendAuthResultMsg(AUTH_FAILED,e);
		}
		if(!thirdResult.checkReturnParamOk())
		{
			Exception e =  new HttpAuthFailedException("doThirdGet","Return Param less");
			sendAuthResultMsg(AUTH_FAILED,e);
		}
		if(!thirdResult.checkStateMatch(state))
		{
			Exception e =  new HttpAuthFailedException("doThirdGet","Return state no match");
			sendAuthResultMsg(AUTH_FAILED,e);
		}

		String codeStr = thirdResult.getCode();
		FinalResult finalResult = doFinalPost(codeStr, clientId, redirectUri);
		Log.debug(this.getClass(), "finalResult = " + finalResult);
		if(!finalResult.isSuc())
		{
			String errStr = finalResult.getErrStr();
			Exception e =  new HttpAuthFailedException("doFinalPost",errStr);
			sendAuthResultMsg(AUTH_FAILED,e);
		}
		if(!finalResult.checkReturnParamOk())
		{
			Exception e =  new HttpAuthFailedException("doFinalPost","Return Param less");
			sendAuthResultMsg(AUTH_FAILED,e);
		}
		sendAuthResultMsg(AUTH_SUC,finalResult);
		//	return finalResult;
	}
	public FirstGetResult doFirstGet(String clientId, String redirectUri,String state) throws Exception
	{
		Log.debug(this.getClass(), "doFirstGet clientId = " + clientId + " redirectUri = " + redirectUri + " state = " + state);
		FirstGetResult result = null;
		String str = getVerifierCode();
		str = EncryptionTool.getSHA256(str);
		if (str == null)
		{
			result = new FirstGetResult(
					FirstGetResult.FirstGetResult_EncryptionEx, "");
			return result;
		}

		Map<String,String> paramsMap = new HashMap<String,String>();
		paramsMap.put("response_type", "code");
		paramsMap.put("client_id", clientId);
		paramsMap.put("scope", getSocpStr());
		paramsMap.put("redirect_uri", redirectUri);
		paramsMap.put("state", state);
		paramsMap.put("acr_values", getAcrStr());
		paramsMap.put("code_challenge", str);
		paramsMap.put("code_challenge_method", getChallengeMethod());

		Response httpResponse = this.operator.httpGetRequest(authUri.toString(), paramsMap);
		int code = httpResponse.code();
		Log.debug(this.getClass(), "doFirstGet code = " + code);
		if (code == 302)
		{
			String desc = httpResponse.body().string();
			result = new FirstGetResult(code, desc);

			String location = httpResponse.header("Location");
			result.setLocation(location);
			if(httpResponse.header("Set-Cookie") != null)
			{
				String cookie = httpResponse.header("Set-Cookie");
				result.setCookie(cookie);
			}
		} else
		{
			String desc = "Error Response: "
					+ httpResponse.code();
			result = new FirstGetResult(code, desc);
		}

		return result;
	}

	public SecondGetResult doSecondGet(String uriPath, String cookie) throws Exception
	{
		Log.debug(this.getClass(), "doSecondGet uriPath = " + uriPath + " cookie = " + cookie );
		SecondGetResult result = null;
		Response httpResponse = this.operator.httpGetRequest(uriPath, cookie);
		int code = httpResponse.code();
		Log.debug(this.getClass(), "doSecondGet code = " + code);
		if (code == 401)
		{
			String desc = httpResponse.body().toString();
			result = new SecondGetResult(code, desc);
//			String url = httpResponse.header("url");
//			result.setUrl(url);
			String authInfo = httpResponse.header("WWW-Authenticate");
			result.setAuthInfo(authInfo);
		}
		else
		{
			String desc = "Error Response: "
					+ httpResponse.body().toString();
			result = new SecondGetResult(code, desc);
		}
		return result;
	}

	public ThirdGetResult doThirdGet(String uriPath, String cookie, String authDscp) throws Exception
	{
		Log.debug(this.getClass(), "doThirdGet uriPath = " + uriPath + " cookie = " + cookie + " authDscp = " + authDscp);
		ThirdGetResult result = null;
		Response httpResponse = this.operator.httpGetRequest(uriPath, cookie,authDscp);
		int code = httpResponse.code();
		Log.debug(this.getClass(), "doThirdGet code = " + code);
		if (code == 302)
		{
			String desc = httpResponse.body().string();
			result = new ThirdGetResult(code, desc);
			String resultStr = httpResponse.header("Location");
			result.setResultStr(resultStr);
		}
		else
		{
			String desc = "Error Response: "
					+ httpResponse.code();
			result = new ThirdGetResult(code, desc);
		}

		return result;
	}

	public FinalResult doFinalPost(String codeStr,String clientId,String redirectUri) throws Exception
	{
		Log.debug(this.getClass(), "doFinalPost codeStr = " + codeStr + " clientId = " + clientId + " redirectUri = " + redirectUri);
		FinalResult result = null;
		Map<String, String> params = new HashMap<String, String>();
		params.put("grant_type", "authorization_code");
		params.put("code", codeStr);
		params.put("client_id", clientId);
		params.put("redirect_uri", redirectUri);
		params.put("code_verifier", getVerifierCode());

		Response httpResponse = this.operator.httpPostRequest(tokenUri.toString(), params);
		int code = httpResponse.code();
		Log.debug(this.getClass(), "doFinalPost code = " + code);
		if (code == 200
				|| code == 400)
		{
			/* ���X�^���r�� */
			String desc = httpResponse.body().string();
			result = new FinalResult(code, desc);
		}
		else
		{
			String desc = "Error Response: "
					+ httpResponse.code();
			result = new FinalResult(code, desc);
		}

		return result;
	}
	public String getAcrStr()
	{
		return "crsc:mc:acr:digest";
	}
	public String getChallengeMethod()
	{
		return "plain";
	}
	protected void initSocpStr()
	{
		StringBuffer strBuf = new StringBuffer(Socp_Openid);
		strBuf.append("%20").append(Socp_Ptt_Svr);
//		strBuf.append("%20").append(Socp_Ptt_Key_Svr);
		strBuf.append("%20").append(Socp_Ptt_Config_Svr);
		strBuf.append("%20").append(Socp_Ptt_Group_Svr);

		strBuf.append("%20").append(Socp_Video_Svr);
		strBuf.append("%20").append(Socp_Video_Key_Svr);
		strBuf.append("%20").append(Socp_Video_Config_Svr);
		strBuf.append("%20").append(Socp_Video_Group_Svr);

		strBuf.append("%20").append(Socp_Data_Svr);
		strBuf.append("%20").append(Socp_Data_Key_Svr);
		strBuf.append("%20").append(Socp_Data_Config_Svr);
		strBuf.append("%20").append(Socp_Data_Group_Svr);
//		strBuf.append("%20").append(Socp_Location_Svr);

		this.socpStr = strBuf.toString();
	}
	public String getState()
	{
		return "abc123";
	}
}
